package com.eslserver.test;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
import java.util.Iterator;
import java.util.List;

import javax.servlet.RequestDispatcher;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.FileUploadException;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.apache.commons.fileupload.servlet.ServletFileUpload;
import org.apache.poi.hssf.usermodel.HSSFCell;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.ss.usermodel.WorkbookFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.eslserver.core.ESLServerPageDispatcher;
import com.eslserver.core.ScheduleTimerInitializer;
import com.eslserver.core.config.AttachmentConfig;
import com.eslserver.dao.CoordinatorDAO;
import com.eslserver.dao.DAOException;
import com.eslserver.dao.ESLDAO;
import com.eslserver.dao.ESLServerDAOFactory;
import com.eslserver.dao.ImageDAO;
import com.eslserver.dao.ScheduleDAO;
import com.eslserver.to.Coordinator;
import com.eslserver.to.ESL;
import com.eslserver.to.Image;
import com.eslserver.to.Schedule;
import com.sun.org.apache.xerces.internal.impl.xpath.regex.ParseException;

@SuppressWarnings("serial")
public class ImportSchedule extends HttpServlet implements
		ESLServerPageDispatcher {
	public static final Logger LOG = LoggerFactory
			.getLogger(ImportSchedule.class);
	private static Date NOWDATE;

	private static final Integer COORD_COLUMN_COUNT = 3;
	private static final Integer IMAGE_COLUMN_COUNT = 2;
	private static final Integer SCHEDULE_COLUMN_COUNT = 7;

	private ArrayList<Image> imageArray = new ArrayList<Image>();

	@Override
	protected void doPost(HttpServletRequest req, HttpServletResponse resp)
			throws ServletException, IOException {

		NOWDATE = new Date();

		if (!ServletFileUpload.isMultipartContent(req)) {
			throw new IllegalArgumentException(
					"Request is not multipart, please 'multipart/form-data' enctype for your form.");
		}

		ServletFileUpload uploadHandler = new ServletFileUpload(
				new DiskFileItemFactory());
		resp.setContentType("text/plain");

		try {
			clearAllData();

			@SuppressWarnings("unchecked")
			List<FileItem> items = uploadHandler.parseRequest(req);

			for (FileItem item : items) {
				if (!item.isFormField()) {
					parseExternalFile(item.getInputStream());
					break; // assume we only get one file at a time
				}
			}

			req.setAttribute(ATTRIBUTE_TAB_ID, SCHEDULE_TAB_ID);
			RequestDispatcher dispatcher = req
					.getRequestDispatcher(MAIN_DASHBOARD);
			dispatcher.forward(req, resp);
		} catch (FileUploadException e) {
			LOG.error(e.getMessage(), e);
		}

		ScheduleTimerInitializer.initScheduleTimer();

	}

	private void parseExternalFile(InputStream inputStream) {

		String eslName;
		String coordName;
		HSSFCell hssfCell;

		String[] coordinatorInfo = new String[COORD_COLUMN_COUNT];
		String[] imageInfo = new String[IMAGE_COLUMN_COUNT];
		String[] scheduleInfo = new String[SCHEDULE_COLUMN_COUNT];

		try {
			Workbook wb = WorkbookFactory.create(inputStream);

			Sheet sheet = wb.getSheetAt(0);
			for (Iterator<Row> iter = sheet.iterator(); iter.hasNext();) {
				Row nowrow = iter.next();

				if (nowrow.getRowNum() > 0) { // real contents
					for (int cellNum = 0; cellNum < coordinatorInfo.length; cellNum++) {
						hssfCell = (HSSFCell) nowrow.getCell(cellNum);
						if (hssfCell == null) {
							coordinatorInfo[cellNum] = "";
						} else {
							coordinatorInfo[cellNum] = convertToString(hssfCell);
						}
					}
					if (coordinatorInfo[0] != null
							&& coordinatorInfo[0].trim().length() != 0) {
						coordName = saveCoordinatorInfo(coordinatorInfo);
						LOG.info("coordName = " + coordName);
					}
				}// END if
			}// END for

			sheet = wb.getSheetAt(1);
			for (Iterator<Row> iter = sheet.iterator(); iter.hasNext();) {
				Row nowrow = iter.next();

				if (nowrow.getRowNum() > 0) { // real contents
					for (int cellNum = 0; cellNum < imageInfo.length; cellNum++) {
						hssfCell = (HSSFCell) nowrow.getCell(cellNum);
						if (hssfCell == null) {
							imageInfo[cellNum] = "";
						} else {
							if (cellNum == 1) {

								File oldFile = new File(
										convertToString(hssfCell));
								if (!oldFile.exists()) {
									LOG.error(oldFile.toString()
											+ " : This file doesn't exist.");
								} else {
									File dir = new File(
											AttachmentConfig.tomcatPath
													+ AttachmentConfig.contextPath
													+ "\\import\\"
													+ new Date().getTime());
									if (!dir.exists()) {
										dir.mkdirs();
									}

									copy(oldFile,
											new File(dir + "\\"
													+ oldFile.getName()));
									imageInfo[cellNum] = dir + "\\"
											+ oldFile.getName();
								}
							} else {
								imageInfo[cellNum] = convertToString(hssfCell);
							}

						}
					}
					if (imageInfo[0] != null
							&& imageInfo[0].trim().length() != 0) {
						Image image = saveImageInfo(imageInfo);
						imageArray.add(image);
					}
				}
			}

			sheet = wb.getSheetAt(2);
			for (Iterator<Row> iter = sheet.iterator(); iter.hasNext();) {
				Row nowrow = iter.next();

				if (nowrow.getRowNum() > 0) { // real contents
					for (int cellNum = 0; cellNum < scheduleInfo.length; cellNum++) {
						hssfCell = (HSSFCell) nowrow.getCell(cellNum);
						if (hssfCell == null) {
							scheduleInfo[cellNum] = "";
						} else {
							scheduleInfo[cellNum] = convertToString(hssfCell);
						}
					}
					if (scheduleInfo[0] != null
							&& scheduleInfo[0].trim().length() != 0) {
						eslName = saveESLScheduleInfo(scheduleInfo);
						LOG.info("eslName = " + eslName);
					}
				}
			}
		} catch (Exception e) {
			LOG.error(e.getMessage(), e);
		}
	}

	private void copy(File oldFile, File newFile) throws IOException {
		InputStream in = new FileInputStream(oldFile);
		OutputStream out = new FileOutputStream(newFile);

		byte[] buf = new byte[1024];
		int len;
		while ((len = in.read(buf)) > 0) {
			out.write(buf, 0, len);
		}
		in.close();
		out.close();
	}

	private static void clearAllData() {
		try {
			CoordinatorDAO coordinatorDAO = ESLServerDAOFactory.getDAOFactory(
					ESLServerDAOFactory.ESLSERVER_DAOFACTORY)
					.getCoordinatorDAO();
			ImageDAO imageDAO = ESLServerDAOFactory.getDAOFactory(
					ESLServerDAOFactory.ESLSERVER_DAOFACTORY).getImageDAO();
			ESLDAO eslDAO = ESLServerDAOFactory.getDAOFactory(
					ESLServerDAOFactory.ESLSERVER_DAOFACTORY).getESLDAO();
			ScheduleDAO scheduleDAO = ESLServerDAOFactory.getDAOFactory(
					ESLServerDAOFactory.ESLSERVER_DAOFACTORY).getScheduleDAO();

			Collection<Coordinator> allCoordinators = coordinatorDAO
					.loadAllCoordinators();
			for (Coordinator coor : allCoordinators) {
				coordinatorDAO.deleteCoordinator(coor.getCoordinatorID());
			}

			Collection<Image> allImages = imageDAO.loadAllImages();
			for (Image image : allImages) {
				imageDAO.deleteImage(image.getImageID());
			}

			Collection<ESL> allESLs = eslDAO.loadAllESLs();
			for (ESL esl : allESLs) {
				eslDAO.deleteESL(esl.getESLID());
			}

			Collection<Schedule> allSchedules = scheduleDAO.loadAllSchedules();
			for (Schedule schedule : allSchedules) {
				scheduleDAO.deleteSchedule(schedule.getScheduleID());
			}

		} catch (DAOException e) {
			LOG.error(e.getMessage(), e);
		}
	}

	private static Image saveImageInfo(String[] imageInfo) {
		Image image = null;
		try {
			ImageDAO imageDAO = ESLServerDAOFactory.getDAOFactory(
					ESLServerDAOFactory.ESLSERVER_DAOFACTORY).getImageDAO();
			image = Image.createImage();

			image.setImageID(Integer.valueOf(imageInfo[0].toString()));
			image.setSystemPath(imageInfo[1].toString());
			imageDAO.addImage(image);
		} catch (DAOException e) {
			LOG.error("Error to add Image.", e);
		} catch (ParseException e) {
			LOG.error("Error to add Image.", e);
		}
		return image;
	}

	private String saveCoordinatorInfo(String[] coordinatorInfo) {
		String coordName = null;

		try {
			CoordinatorDAO coordinatorDAO = ESLServerDAOFactory.getDAOFactory(
					ESLServerDAOFactory.ESLSERVER_DAOFACTORY)
					.getCoordinatorDAO();
			Coordinator coordinator = Coordinator.createESLCoordinator();

			coordinator.setName(coordinatorInfo[0].toString());
			coordinator.setIpAddress(coordinatorInfo[1].toString());
			coordinator.setPort(Integer.valueOf(coordinatorInfo[2].toString()));
			coordinatorDAO.addCoordinator(coordinator);

			coordName = coordinator.getName();
		} catch (DAOException e) {
			LOG.error("Error to add Coordinator.", e);
		} catch (ParseException e) {
			LOG.error("Error to add Coordinator.", e);
		}
		return coordName;
	}

	private String saveESLScheduleInfo(String[] eslInfo) {
		String eslName = null;

		try {
			ESLDAO eslDAO = ESLServerDAOFactory.getDAOFactory(
					ESLServerDAOFactory.ESLSERVER_DAOFACTORY).getESLDAO();
			ScheduleDAO scheduleDAO = ESLServerDAOFactory.getDAOFactory(
					ESLServerDAOFactory.ESLSERVER_DAOFACTORY).getScheduleDAO();
			CoordinatorDAO coordinatorDAO = ESLServerDAOFactory.getDAOFactory(
					ESLServerDAOFactory.ESLSERVER_DAOFACTORY)
					.getCoordinatorDAO();

			ESL esl = ESL.createESL();
			Schedule schedule1 = Schedule.createSchedule();
			Schedule schedule2 = Schedule.createSchedule();
			Schedule schedule3 = Schedule.createSchedule();

			esl.setName(eslInfo[0].toString());
			esl.setMacAddress(eslInfo[1].toString());
			Coordinator coor = coordinatorDAO.loadCoordinatorByName(eslInfo[2]
					.toString());
			esl.setCoordinator(coor);
			esl.setImages(imageArray);
			eslDAO.addESL(esl);

			Date schedule1Date = new Date(NOWDATE.getTime()
					+ Integer.valueOf(eslInfo[3]) * 1000);
			schedule1.setName(esl.getName() + "Schedule1");
			schedule1.setStartTime(schedule1Date);
			schedule1.setRepeat(true);
			schedule1.setTimeInterval(Integer.valueOf(eslInfo[6].toString()));
			schedule1.setEsl(esl);
			schedule1.setImage(imageArray.get(0));
			scheduleDAO.addSchedule(schedule1);

			Date schedule2Date = new Date(schedule1Date.getTime()
					+ Integer.valueOf(eslInfo[4]) * 1000);
			schedule2.setName(esl.getName() + "Schedule2");
			schedule2.setStartTime(schedule2Date);
			schedule2.setRepeat(true);
			schedule2.setTimeInterval(Integer.valueOf(eslInfo[6].toString()));
			schedule2.setEsl(esl);
			schedule2.setImage(imageArray.get(1));
			scheduleDAO.addSchedule(schedule2);

			Date schedule3Date = new Date(schedule2Date.getTime()
					+ Integer.valueOf(eslInfo[5]) * 1000);
			schedule3.setName(esl.getName() + "Schedule3");
			schedule3.setStartTime(schedule3Date);
			schedule3.setRepeat(true);
			schedule3.setTimeInterval(Integer.valueOf(eslInfo[6].toString()));
			schedule3.setEsl(esl);
			schedule3.setImage(imageArray.get(2));
			scheduleDAO.addSchedule(schedule3);

			eslName = esl.getName();
		} catch (DAOException e) {
			LOG.error("Error to add ESL.", e);
		} catch (ParseException e) {
			LOG.error("Error to add ESL.", e);
		}
		return eslName;
	}

	private static String convertToString(HSSFCell cell) {
		String ret = "";

		if (cell != null) {
			int type = cell.getCellType();
			switch (type) {
			case HSSFCell.CELL_TYPE_BLANK:
			case HSSFCell.CELL_TYPE_BOOLEAN:
			case HSSFCell.CELL_TYPE_ERROR:
			case HSSFCell.CELL_TYPE_FORMULA:
				break;
			case HSSFCell.CELL_TYPE_NUMERIC:
				ret += (long) cell.getNumericCellValue();
				if (ret.indexOf(".") >= 0) {
					ret = ret.substring(0, ret.indexOf("."));
				}
				break;
			case HSSFCell.CELL_TYPE_STRING:
				ret = cell.getStringCellValue();
				break;
			}
		}
		return ret;
	}
}